/**
 * 悬停管理器
 *
 * 功能说明：
 * 1. 管理鼠标悬停在甘特图上的高亮效果
 * 2. 提供十字线高亮（行、列、单元格）
 * 3. 计算悬停位置和状态信息
 * 4. 支持悬停效果的配置和自定义
 *
 * 设计模式：单例模式 + 状态管理
 */

// ========== 悬停状态接口 ==========

/**
 * 悬停状态接口
 * 记录当前鼠标悬停的详细信息
 */
export interface HoverState {
  roomIndex: number; // 房间行索引
  dateIndex: number; // 日期列索引
  roomId: string; // 房间ID
  date: string; // 日期字符串
  isHovering: boolean; // 是否正在悬停
  timestamp: number; // 悬停时间戳
}

/**
 * 十字线高亮配置接口
 * 控制悬停时的高亮显示效果
 */
export interface CrossHairState {
  showRowHighlight: boolean; // 是否显示行高亮（整行高亮）
  showColumnHighlight: boolean; // 是否显示列高亮（整列高亮）
  showCellHighlight: boolean; // 是否显示单元格高亮（交叉点高亮）
  highlightOpacity: number; // 高亮透明度（0-1）
}

// ========== 悬停管理器类 ==========

/**
 * 悬停管理器类
 * 负责管理鼠标悬停时的所有高亮效果和状态计算
 */
export class HoverManager {
  // ========== 私有属性 ==========

  /**
   * 当前悬停状态
   * 记录鼠标当前悬停的单元格信息
   */
  private currentHover: HoverState | null = null;

  /**
   * 十字线高亮配置
   * 控制悬停时的高亮显示效果
   */
  private crossHairConfig: CrossHairState;

  /**
   * 房间数据数组
   * 用于根据索引查找房间信息
   */
  private rooms: any[] = [];

  /**
   * 日期数据数组
   * 用于根据索引查找日期信息
   */
  private dates: string[] = [];

  /**
   * 甘特图配置
   * 包含单元格尺寸、位置等配置信息
   */
  private config: any = {};

  /**
   * 构造函数
   * 初始化十字线高亮配置
   */
  constructor() {
    this.crossHairConfig = {
      showRowHighlight: true, // 默认显示行高亮
      showColumnHighlight: true, // 默认显示列高亮
      showCellHighlight: true, // 默认显示单元格高亮
      highlightOpacity: 0.15, // 默认透明度15%
    };
  }

  // ========== 公共方法 ==========

  /**
   * 初始化悬停管理器
   * 设置房间数据、日期数据和甘特图配置
   * @param rooms 房间数据数组
   * @param dates 日期数据数组
   * @param config 甘特图配置对象
   */
  initialize(rooms: any[], dates: string[], config: any): void {
    this.rooms = rooms;
    this.dates = dates;
    this.config = config;
    console.log('悬停管理器初始化完成');
  }

  /**
   * 更新悬停状态
   * 根据鼠标坐标计算悬停的单元格，并更新悬停状态
   * @param x 鼠标X坐标
   * @param y 鼠标Y坐标
   * @returns 悬停状态对象，如果无效则返回null
   */
  updateHover(x: number, y: number): HoverState | null {
    // 检查是否在有效区域内（排除房间信息列）
    if (x < this.config.roomTypeWidth + this.config.roomNumberWidth) {
      this.clearHover();
      return null;
    }

    // 计算房间索引和日期索引
    const dateIndex = Math.floor(
      (x - this.config.roomTypeWidth - this.config.roomNumberWidth) /
        this.config.cellWidth
    );
    const roomIndex = Math.floor(y / this.config.cellHeight);

    // 检查索引有效性，确保在数据范围内
    if (
      dateIndex < 0 ||
      dateIndex >= this.dates.length ||
      roomIndex < 0 ||
      roomIndex >= this.rooms.length
    ) {
      this.clearHover();
      return null;
    }

    const room = this.rooms[roomIndex];
    const date = this.dates[dateIndex];

    // 更新悬停状态
    this.currentHover = {
      roomIndex,
      dateIndex,
      roomId: room.id,
      date,
      isHovering: true,
      timestamp: Date.now(),
    };

    return this.currentHover;
  }

  /**
   * 清除悬停状态
   * 重置当前悬停状态为null
   */
  clearHover(): void {
    this.currentHover = null;
  }

  /**
   * 获取当前悬停状态
   * @returns 当前悬停状态对象，如果没有悬停则返回null
   */
  getCurrentHover(): HoverState | null {
    return this.currentHover;
  }

  // ========== 悬停状态检查方法 ==========

  /**
   * 检查是否悬停在指定单元格
   * @param roomIndex 房间行索引
   * @param dateIndex 日期列索引
   * @returns 是否悬停在该单元格
   */
  isHoveringCell(roomIndex: number, dateIndex: number): boolean {
    return (
      this.currentHover?.roomIndex === roomIndex &&
      this.currentHover?.dateIndex === dateIndex
    );
  }

  /**
   * 检查是否悬停在指定行
   * @param roomIndex 房间行索引
   * @returns 是否悬停在该行
   */
  isHoveringRow(roomIndex: number): boolean {
    return this.currentHover?.roomIndex === roomIndex;
  }

  /**
   * 检查是否悬停在指定列
   * @param dateIndex 日期列索引
   * @returns 是否悬停在该列
   */
  isHoveringColumn(dateIndex: number): boolean {
    return this.currentHover?.dateIndex === dateIndex;
  }

  // ========== 高亮区域计算方法 ==========

  /**
   * 获取行高亮区域
   * 计算整行的高亮显示区域坐标和尺寸
   * @returns 行高亮区域信息，如果没有悬停则返回null
   */
  getRowHighlightArea(): {
    x: number;
    y: number;
    width: number;
    height: number;
  } | null {
    if (!this.currentHover) return null;

    return {
      x: 0, // 从最左边开始
      y: this.currentHover.roomIndex * this.config.cellHeight, // 行位置
      width:
        this.config.roomTypeWidth +
        this.config.roomNumberWidth +
        this.dates.length * this.config.cellWidth, // 整行宽度
      height: this.config.cellHeight, // 行高度
    };
  }

  /**
   * 获取列高亮区域
   * 计算整列的高亮显示区域坐标和尺寸
   * @returns 列高亮区域信息，如果没有悬停则返回null
   */
  getColumnHighlightArea(): {
    x: number;
    y: number;
    width: number;
    height: number;
  } | null {
    if (!this.currentHover) return null;

    return {
      x:
        this.config.roomTypeWidth +
        this.config.roomNumberWidth +
        this.currentHover.dateIndex * this.config.cellWidth, // 列位置
      y: 0, // 从最上面开始
      width: this.config.cellWidth, // 列宽度
      height: this.rooms.length * this.config.cellHeight, // 整列高度
    };
  }

  /**
   * 获取单元格高亮区域
   * 计算当前悬停单元格的高亮显示区域坐标和尺寸
   * @returns 单元格高亮区域信息，如果没有悬停则返回null
   */
  getCellHighlightArea(): {
    x: number;
    y: number;
    width: number;
    height: number;
  } | null {
    if (!this.currentHover) return null;

    return {
      x:
        this.config.roomTypeWidth +
        this.config.roomNumberWidth +
        this.currentHover.dateIndex * this.config.cellWidth, // 单元格X位置
      y: this.currentHover.roomIndex * this.config.cellHeight, // 单元格Y位置
      width: this.config.cellWidth, // 单元格宽度
      height: this.config.cellHeight, // 单元格高度
    };
  }

  // ========== 配置管理方法 ==========

  /**
   * 设置十字线配置
   * 更新悬停高亮的显示配置
   * @param config 部分配置对象
   */
  setCrossHairConfig(config: Partial<CrossHairState>): void {
    this.crossHairConfig = { ...this.crossHairConfig, ...config };
  }

  /**
   * 获取十字线配置
   * @returns 当前十字线配置对象
   */
  getCrossHairConfig(): CrossHairState {
    return this.crossHairConfig;
  }

  // ========== 信息显示方法 ==========

  /**
   * 获取悬停信息文本
   * 生成悬停时显示的文本信息
   * @returns 悬停信息文本
   */
  getHoverInfo(): string {
    if (!this.currentHover) return '';

    const room = this.rooms[this.currentHover.roomIndex];
    const date = this.currentHover.date;
    const roomType = this.getRoomTypeName(room.roomType);

    return `${roomType} ${room.roomNumber} - ${date}`;
  }

  /**
   * 获取房间类型名称
   * 将房间类型枚举转换为中文显示名称
   * @param roomType 房间类型枚举值
   * @returns 中文房间类型名称
   */
  private getRoomTypeName(roomType: string): string {
    const typeNames: Record<string, string> = {
      standard_single: '标准单人间',
      deluxe_king: '豪华大床房',
      executive_suite: '行政套房',
    };
    return typeNames[roomType] || roomType;
  }

  /**
   * 获取相对日期描述
   * 将日期转换为相对于今天的描述（如"今天"、"明天"、"3天后"等）
   * @param date 日期字符串（格式：MM/DD）
   * @returns 相对日期描述
   */
  getRelativeDateDescription(date: string): string {
    const today = new Date();
    const [month, day] = date.split('/').map(Number);
    const targetDate = new Date(today.getFullYear(), month - 1, day);

    const diffTime = targetDate.getTime() - today.getTime();
    const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24));

    if (diffDays === 0) return '今天';
    if (diffDays === 1) return '明天';
    if (diffDays === 2) return '后天';
    if (diffDays > 0) return `${diffDays}天后`;
    if (diffDays === -1) return '昨天';
    if (diffDays < 0) return `${Math.abs(diffDays)}天前`;

    return date;
  }
}

// ========== 导出单例实例 ==========

/**
 * 悬停管理器单例实例
 * 全局唯一的悬停管理器实例，供整个应用使用
 */
export const hoverManager = new HoverManager();
